#include "internal.h"
#include "Defines.h"
#include "DeviceProperty.h"
#include "PortableDeviceProps.h"
#include "PortableDeviceProps.tmh"

CPortableDeviceProps::CPortableDeviceProps(void)
{
	m_hrCreate = Init();
}

HRESULT CPortableDeviceProps::Init()
{
	//
	// create the key and value objects
	//
	HRESULT hr;
	hr = m_pKeys.CoCreateInstance(CLSID_PortableDeviceKeyCollection);
	if(SUCCEEDED(hr))
		hr = m_pValues.CoCreateInstance(CLSID_PortableDeviceValues);

	return hr;
}

CPortableDeviceProps::CPortableDeviceProps(CDeviceProperty *prop, ...)
{
	//
	// initialize object
	//
	m_hrCreate = Init();

	if(SUCCEEDED(m_hrCreate))
	{
		//
		// process the params
		//
		va_list marker;
		CDeviceProperty *p = prop;
		vector<CDeviceProperty *> props;

		va_start(marker, prop);
		while( p != NULL )
		{
			props.push_back(p);
			p = va_arg(marker, CDeviceProperty*);
		}
		va_end(marker);
		m_hrCreate = InternalAddProps(props);
	}
}

HRESULT CPortableDeviceProps::AddProps(CDeviceProperty *prop, ...)
{
	//
	// if create failed then we can't do anything
	//
	if(FAILED(m_hrCreate))
		return m_hrCreate;

	va_list marker;
    CDeviceProperty *p = prop;
	vector<CDeviceProperty *> props;

	va_start(marker, prop);
    while( p != NULL )
    {
		props.push_back(p);
        p = va_arg(marker, CDeviceProperty*);
    }
    va_end(marker);

	return InternalAddProps(props);
}

HRESULT CPortableDeviceProps::InternalAddProps(vector<CDeviceProperty *> props)
{
	//
	// if create failed then we can't do anything
	//
	if(FAILED(m_hrCreate))
		return m_hrCreate;

	//
	// add the keys to the keys collection and values to
	// the values collection
	//
	HRESULT hr;
	for(vector<CDeviceProperty *>::const_iterator it = props.begin() ;
		it != props.end() ; ++it)
	{
		const CDeviceProperty *pProp = *it;
		hr = m_pKeys->Add(*(pProp->m_key));
		if(FAILED(hr))
			return hr;
		hr = m_pValues->SetValue(*(pProp->m_key), &(pProp->m_value));
		if(FAILED(hr))
			return hr;
	}

	return S_OK;
}

HRESULT CPortableDeviceProps::Clear()
{
	//
	// if create failed then we can't do anything
	//
	if(FAILED(m_hrCreate))
		return m_hrCreate;

	HRESULT hrk = m_pKeys->Clear();
	HRESULT hrv = m_pValues->Clear();

	if(FAILED(hrk))
		return hrk;
	if(FAILED(hrv))
		return hrv;
	return S_OK;
}

HRESULT CPortableDeviceProps::SetValue(REFPROPERTYKEY key, const PROPVARIANT &value)
{
	//
	// if create failed then we can't do anything
	//
	if(FAILED(m_hrCreate))
		return m_hrCreate;

	//
	// if this key already exists then just update value; otherwise
	// add the key
	//
	PROPVARIANT pvar;
	PropVariantInit(&pvar);
	HRESULT hr = m_pValues->GetValue(key, &pvar);
	if(hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND))
		hr = m_pKeys->Add(key);
	if(FAILED(hr))
		return hr;

	return m_pValues->SetValue(key, &value);
}

HRESULT CPortableDeviceProps::SetError(REFPROPERTYKEY key, HRESULT code)
{
	//
	// if this key already exists then just update value; otherwise
	// add the key
	//
	PROPVARIANT pvar;
	PropVariantInit(&pvar);
	HRESULT hr = m_pValues->GetValue(key, &pvar);
	if(hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND))
		hr = m_pKeys->Add(key);
	if(FAILED(hr))
		return hr;

	return m_pValues->SetErrorValue(key, code);
}

template<typename T>
HRESULT CPortableDeviceProps::GetValue(REFPROPERTYKEY key, T& val)
{
	//
	// if create failed then we can't do anything
	//
	if(FAILED(m_hrCreate))
		return m_hrCreate;

	//
	// get the value for this key and load it up into
	// a "CDeviceProperty" object
	//
	CDeviceProperty prop;
	HRESULT hr;

	hr = m_pValues->GetValue(key, &prop.m_value);
	if(SUCCEEDED(hr))
		val = prop;

	return hr;
}
